//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "InvoiceDlg.h"
#include "FormUtilities.h"
#include "Calendar.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

const int CODE_DATE    = 1;
const int CODE_PAGE    = 2;
const int CODE_INVOICE = 3;
const int CODE_AMOUNT  = 4;

//---------------------------------------------------------------------------

__fastcall TfrmInvoiceDlg::TfrmInvoiceDlg(TComponent* Owner, TDatabase* dbMain, TInvoiceBridge* bridge, TInvoice* invoice)
        : TForm(Owner)
{
   TFormUtilities::LocateForm(( TForm*)Owner, this);

   this->bridge  = bridge;
   this->invoice = invoice;
   lblCurrency->Caption = "(" + CurrencyString + ")";

   ptBridge = new TPaymentTypeBridge(dbMain);
   cmbPaymentTypes->Sorted = true;
   FillPaymentTypesCombo();   

   if ( invoice == NULL)
   {
      Caption = "Add new invoice";
      original = NULL;
   }
   else
   {
      Caption = "Update invoice";
      original = new TInvoice( invoice);
      ShowInvoice();
   }//if-else
}

void TfrmInvoiceDlg :: FillPaymentTypesCombo()
{
   ptBridge->GetPaymentTypes( cmbPaymentTypes->Items);
   if (cmbPaymentTypes->Items->Count > 0)
        cmbPaymentTypes->ItemIndex = 0;
}

void TfrmInvoiceDlg :: ShowInvoice()
{
   edtDate->Text    = DateToStr( invoice->date);
   edtPage->Text    = IntToStr( invoice->page);
   edtInvoice->Text = IntToStr( invoice->invoiceID);
   edtAmount->Text  = FloatToStr( invoice->amount);

   int i = 0;
   bool found = false;

   while (( i < cmbPaymentTypes->Items->Count) && ( !found))
   {
      TPaymentType* pt = (TPaymentType*)cmbPaymentTypes->Items->Objects[ i];
      if ( pt->id == invoice->paymentType->id)
         found = true;
      else
         i++;     
   }

   if (found)
      cmbPaymentTypes->ItemIndex = i;
   else
      cmbPaymentTypes->ItemIndex = -1;
}

void TfrmInvoiceDlg :: GatherInvoice()
{
   invoice->date       = StrToDate( edtDate->Text);
   invoice->page       = StrToInt( edtPage->Text);
   invoice->invoiceID  = StrToInt( edtInvoice->Text);
   invoice->amount     = StrToFloat( edtAmount->Text);
   TPaymentType* pt = (TPaymentType*)cmbPaymentTypes->Items->Objects[ cmbPaymentTypes->ItemIndex];
   invoice->paymentType->id = pt->id;
   invoice->isCanceled = false;
}

bool TfrmInvoiceDlg :: IsGapExist( TInvoiceBridge * bridge, TInvoice * origInvoice, TInvoice * currInvoice)
{
   TStringList * invoices;
   TInvoice * curr;
   TInvoice * next;
   bool gapExists;
   bool allowed;
   int i;

   invoices = new TStringList();

   try
   {
      invoices->Sorted = true;
      if ( currInvoice == NULL)
         bridge->GetPageInvoices( origInvoice->page, invoices);
      else
         bridge->GetPageInvoices( currInvoice->page, invoices);
         
      if ( origInvoice != NULL)
      {
         i = invoices->IndexOf( IntToStr( origInvoice->invoiceID));
         if ( i >= 0)
         {
            origInvoice = ( TInvoice *)invoices->Objects[ i];
            invoices->Delete( i);
            delete origInvoice;
         }//if   
      }//if

      if ( currInvoice != NULL)
      {
         curr = new TInvoice( currInvoice);
         invoices->AddObject( IntToStr( curr->invoiceID), curr);
      }//if

      for ( i = 0, gapExists = false; i < invoices->Count && !gapExists; i++)
      {
         curr = ( TInvoice *)invoices->Objects[ i];

         if ( i < invoices->Count - 1)
            next = ( TInvoice *)invoices->Objects[ i + 1];
         else
            next = NULL;   

         if (( i == 0) && ( curr->invoiceID != 1))
            gapExists = true;
         else
            gapExists = ( next != NULL) && ( next->invoiceID - curr->invoiceID != 1);    
      }//for
   }
   __finally
   {
      TStringUtilites :: Clear( invoices);
      delete invoices;
   }//try-finally

   return gapExists;
}

bool TfrmInvoiceDlg :: IsActionAllowed( TInvoiceBridge * bridge, TInvoice * origInvoice, TInvoice * currInvoice)
{
   bool allowed;
   bool gapExists;

   allowed = true;
   gapExists = IsGapExist( bridge, origInvoice, currInvoice);
   
   if ( gapExists)
   {
      if ( MessageDlg( "Gap in invoice numbers will be created!\nAre you sure?",
                       mtWarning,
                       TMsgDlgButtons() << mbYes << mbNo,
                       0) == mrNo)
      {
         allowed = false;
      }//if
   }//if

   return allowed;
}

void TfrmInvoiceDlg :: AddNewInvoice()
{
   bool doAdd;

   invoice = new TInvoice();

   try
   {
      GatherInvoice();

      if ( bridge->IsExist( invoice->page, invoice->invoiceID))
         throw new TError( CODE_DATE, "Invoice already exists");

      doAdd = IsActionAllowed( bridge, NULL, invoice);

      if ( doAdd)
         bridge->Add( bridge->GetNextID(), invoice);
      else
         ModalResult = mrNone;   
   }
   __finally
   {
      delete invoice;
      invoice = NULL;
   }//try-finally
}

void TfrmInvoiceDlg :: UpdateInvoice()
{
   bool doUpdate;

   GatherInvoice();

   if (( !original->IsEqual( invoice)) && ( bridge->IsExist( invoice->page, invoice->invoiceID)))
      throw new TError( CODE_DATE, "Invoice already exists");

   doUpdate = IsActionAllowed( bridge, original, invoice);

   if ( doUpdate)
      bridge->Update( invoice->id, invoice);
   else
      ModalResult = mrNone;
}

void TfrmInvoiceDlg :: ValidateData()
{
   __int64 invoiceNum;

   if ( edtDate->Text.Length() == 0)
      throw new TError( CODE_DATE, "Date must be entered");

   try
   {
      TDateUtilities::validate( edtDate->Text, "Illegal date");
   }
   catch( Exception * e)
   {
      throw new TError( CODE_DATE, e->Message);
   }//try-catch

   if ( edtPage->Text.Length() == 0)
      throw new TError( CODE_PAGE, "Page must be entered");

   try
   {
      StrToInt( edtPage->Text);
   }
   catch( Exception * e)
   {
      throw new TError( CODE_PAGE,  "Illegal page");
   }//try-catch

   if ( edtInvoice->Text.Length() == 0)
      throw new TError( CODE_INVOICE, "Invoice must be entered");

   try
   {
      invoiceNum = StrToInt( edtInvoice->Text);
   }
   catch( Exception * e)
   {
      throw new TError( CODE_INVOICE, "Illegal invoice");
   }//try-catch

   if (( invoiceNum < MIN_INVOICE_NUM) || ( invoiceNum > MAX_INVOICE_NUM))
   {
      throw new TError( CODE_INVOICE, "Invoice number must be a value between " + IntToStr( MIN_INVOICE_NUM) + " and " + IntToStr( MAX_INVOICE_NUM));
   }//if

   if ( edtAmount->Text.Length() == 0)
      throw new TError( CODE_AMOUNT, "Amount must be entered");

   try
   {
      StrToFloat( edtAmount->Text);
   }
   catch( Exception * e)
   {
      throw new TError( CODE_AMOUNT, "Illegal amount");
   }//try-catch
}

void TfrmInvoiceDlg :: HandleError( TError * e)
{
   MessageDlg( e->Message,
               mtError,
               TMsgDlgButtons() << mbOK,
               0);

   switch ( e->GetCode())
   {
      case CODE_DATE :
         edtDate->SetFocus();
         break;

      case CODE_PAGE :
         edtPage->SetFocus();
         break;

      case CODE_INVOICE :
         edtInvoice->SetFocus();
         break;

      case CODE_AMOUNT :
         edtAmount->SetFocus();
         break;
   }//switch

   ModalResult = mrNone;
}

//---------------------------------------------------------------------------

void __fastcall TfrmInvoiceDlg::btnOKClick(TObject *Sender)
{
   try
   {
      ValidateData();
      
      if ( invoice == NULL)
         AddNewInvoice();
      else
         UpdateInvoice();
   }
   catch( TError * e)
   {
      HandleError( e);
   }//try-catch
}
//---------------------------------------------------------------------------


void __fastcall TfrmInvoiceDlg::btnDateClick(TObject *Sender)
{
   TfrmCalendar * frmCalendar;

   frmCalendar = new TfrmCalendar( this);

   try
   {
      if ( edtDate->Text.Length() > 0)
         frmCalendar->calendar->Date = StrToDate( edtDate->Text);

      if ( frmCalendar->ShowModal() == mrOk)
         edtDate->Text = DateToStr( frmCalendar->calendar->Date);
   }
   __finally
   {
      delete frmCalendar;
   }
}
//---------------------------------------------------------------------------

void __fastcall TfrmInvoiceDlg::FormDestroy(TObject *Sender)
{
   if ( original != NULL)
      delete original;        
}
//---------------------------------------------------------------------------



void __fastcall TfrmInvoiceDlg::edtInvoiceEnter(TObject *Sender)
{
   if (edtInvoice->Text.IsEmpty())
   {
      if (!edtPage->Text.IsEmpty())
      {
            try
            {
               int page = StrToInt(edtPage->Text);
               TStringList * invoices = new TStringList();
               try
               {
                  int nextInvoiceID;
                  invoices->Sorted = true;
                  bridge->GetPageInvoices(page, invoices);
                  int numOfInvoices = invoices->Count;
                  if (numOfInvoices > 0)
                  {
                     TInvoice* lastInvoice = (TInvoice*)invoices->Objects[numOfInvoices - 1];
                     if (lastInvoice->invoiceID < MAX_INVOICE_NUM)
                     {
                        nextInvoiceID = lastInvoice->invoiceID + 1;
                     }
                     else
                     {
                        nextInvoiceID = NO_ID;
                     }
                  }
                  else
                  {
                     nextInvoiceID = 1;
                  }

                  if (nextInvoiceID != NO_ID)
                  {
                     edtInvoice->Text = nextInvoiceID;
                  }
               }
               __finally
               {
                  TStringUtilites::Clear(invoices);
                  delete invoices;
               }
            }
            catch( Exception * e)
            {
               //do nothing
            }//try-catch
      }
   }
}
//---------------------------------------------------------------------------

